package com.gitee.wsl.ext.reflect

import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.KMutableProperty0
//import kotlin.reflect.full.declaredMembers

object ReflectionExt {
   /**
    * Returns the package name of `clazz` according to the Java Language Specification (section
    * 6.7). Unlike [Class.getPackage], this method only parses the class name, without
    * attempting to define the [Package] and hence load files.
    */
   fun getPackageName(clazz: KClass<*>): String {
      return getPackageName(clazz.simpleName!!)
   }

   /**
    * Returns the package name of `classFullName` according to the Java Language Specification
    * (section 6.7). Unlike [Class.getPackage], this method only parses the class name, without
    * attempting to define the [Package] and hence load files.
    */
   fun getPackageName(classFullName: String): String {
      val lastDot = classFullName.lastIndexOf('.')
      return if (lastDot < 0) "" else classFullName.substring(0, lastDot)
   }

   /**
    * @param name name of the constant, case-insensitive
    * @param T class to extract the constant from **and** the value type
    * @return value of the constant with the given name if found, `null` otherwise
    */
//   inline fun <reified T> getConstantByName(name: String): T? =
//      T::class.declaredMembers.find { it.name.equals(name, ignoreCase = true) }?.call() as? T
}



inline fun <T, R> keep(mut: KMutableProperty0<T>, block: () -> R): R {
   val temp = mut.get()
   try {
      return block()
   } finally {
      mut.set(temp)
   }
}

/*@Suppress("UnstableApiUsage")
val <T> Class<T>.getPackageName: String
   get() = ReflectionExt.getPackageName(this)



inline fun <reified T, V> V.createObject():T{
   T::class.constructors.forEach {
      return it.call(this)
   }
   throw IllegalArgumentException("value type $this")
}*/

/**
 * Updates the value of the field with the specified name to the given value.
 * This involves temporarily setting the `accessible` flag to `true`.
 */
/* inline fun <reified T, V> T.setFieldValue(fieldName: String, value: V) {
    val field = T::class.java.getDeclaredField(fieldName)
    val wasAccessible = field.isAccessible
    field.isAccessible = true
    field.set(this, value)
    field.isAccessible = wasAccessible
}*/

/**
 * Returns the value of the field with the specified name.
 * This involves temporarily setting the `accessible` flag to `true`.
 */
/*@Suppress("UNCHECKED_CAST")
 inline fun <reified T, V> T.getFieldValue(fieldName: String): V {
    val field = T::class.java.getDeclaredField(fieldName)
    val wasAccessible = field.isAccessible
    field.isAccessible = true
    val value = field.get(this) as V
    field.isAccessible = wasAccessible
    return value
}*/

/*
class Ref<T>(var varRef:KMutableProperty<T>): ReadWriteProperty<Any, T> {
    init {
        varRef.isAccessible=true
    }
   override fun getValue(thisRef: Any, property: KProperty<*>): T {
     return varRef.getter
   }

   override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {

   }

}*/

/*fun <E : Enum<E>> E.next(): E? = declaringJavaClass.enumConstants.run {
   this?.get((ordinal + 1) % size)
}

fun <E : Enum<E>> E.previous(): E? = declaringJavaClass.enumConstants.run {
   this?.get((ordinal - 1).mod(size))
}*/


/**
 * Description:
 * @author Junerver
 * date: 2024/2/2-8:02
 * Email: junerver@gmail.com
 * Version: v1.0
 */

// 原始函数模型 (TParams) -> TData
typealias TParams = Array<Any?> // 原函数可变长度的参数

// 对所有函数固定抽象
typealias NormalFunction<TData> = (TParams) -> TData
typealias SuspendNormalFunction<TData> = suspend (TParams) -> TData
typealias VoidFunction = NormalFunction<Unit>
typealias SuspendVoidFunction = SuspendNormalFunction<Unit>

// 最常规的函数 ()->Unit
typealias NoParamsVoidFunction = KFunction<Unit>

/**
 * 优化函数调用形式，将导出的函数伪装成普通函数的样子，无需对参数进行[arrayOf]，可能需要手动导包：
 * ```
 * import xyz.junerver.compose.hooks.invoke
 * ```
 */
operator fun <TData> NormalFunction<TData>.invoke(vararg params: Any?) = this(arrayOf(*params))
operator fun VoidFunction.invoke(vararg params: Any?) = this(arrayOf(*params))

typealias DependencyList = Array<out Any>

/**
 * 用来将任意一个函数转换成 noop 函数。但是需要注意，如果这个函数是一个实例的函数，必须要传入对应的实例。
 *
 * 注意不能应用于 Composable 内部的函数，只能应用于外部的、非 Composable 的函数。
 *
 * 例如：
 * ```kotlin
 * interface TestInt {
 *     fun addadd(a: Int, b: Int)
 * }
 * class TestAbs() : TestInt {
 *     override fun addadd(a: Int, b: Int) {
 *         println("实现类：" + (a + b))
 *     }
 * }
 * @Test
 * fun testCallWrapFn() {
 *     TestAbs().addadd(1, 2)
 *     // 第一个参数是实例
 *     TestInt::addadd.toNoopFn(TestAbs())(arrayOf(4, 5))
 *     TestInt::addadd.toNoopFn()(arrayOf(TestAbs(), 4, 5))
 * }
 * ```
 *
 * 注意 Compose 编译魔法！例如一个 Composable 内的简单的局部函数：
 * ```
 * fun add() {
 *   ++count
 * }
 * ```
 * 他看起来是一个无参数的普通函数，如果我们转换成 [NormalFunction] 将会出现运行时错误。
 * 经过 Compose 插件编译后，这个函数的实际签名是：
 * Function 'add' (JVM signature: TestUndoScreen$add(Landroidx/compose/runtime/MutableIntState;)V)，
 * 它变成了`TestUndoScreen$add`，而且还多了一个参数，意味着我们在调用 noop 时将会缺少实例
 * (Composable 是个函数，我们拿不到其实例)，从而抛出异常。
 *
 * @param instance 对应函数的实例，如果是顶层函数可以不传递。
 *
 */
/*
fun <T> KFunction<T?>.asNoopFn(instance: Any? = null): (TParams) -> T? = fun(params: TParams): T? =
   this.call(*synthesisParametersAndCheck(instance, params, this))
*/

/**
 * 将一个 [suspend] 挂起函数转换成[suspend] 版本的 [NormalFunction] 函数。
 * 直接使用 [asNoopFn] 会抛出异常，因为挂起函数的参数比参数列表还多一个挂起相关标识。
 */
/*fun <T : Any> KFunction<T>.asSuspendNoopFn(instance: Any? = null): suspend (TParams) -> T {
   require(this.isSuspend) { "The function type is incorrect, and it must be a 'suspend' function" }
   suspend fun run(params: TParams): T =
      this.callSuspend(*synthesisParametersAndCheck(instance, params, this))
   return ::run
}*/

/*fun <T> synthesisParametersAndCheck(instance: Any?, params: TParams, fn: KFunction<T?>): TParams {
   val finalParams = instance?.let { arrayOf(it, *params) } ?: params
   checkIsLegalParameters(fn, *finalParams)
   return finalParams
}*/

//typealias PauseFn = KFunction<Unit>
//typealias ResumeFn = KFunction<Unit>
//typealias IsActive = Boolean


/**
 * Description:
 * @author Junerver
 * date: 2024/1/31-10:38
 * Email: junerver@gmail.com
 * Version: v1.0
 */

/**
 * 用于检测包装函数是否合法，例如：
 * ```
 * fun originFn(string: String, i: Int): String {
 *     return "output: $string ----- $i"
 * }
 * fun originFnWraped(vararg prams: Any): String {
 *     checkIsLegalParameters(::originFn, *prams)
 *     return originFn(prams[0] as String, prams[1] as Int)
 * }
 * ```
 * 需要注意的一点是如果这是一个接口里的抽象方法，那么参数数量会比函数签名多一个，其类型就是接口本身。
 *
 *
 */
/*fun checkIsLegalParameters(fn: KFunction<*>, vararg params: Any?) {
   require(fn.parameters.size == params.size) {
      "Number of fn:${fn.name} parameters does not match. Expected: ${fn.parameters.size}, Actual: ${params.size}"
   }

   val realFnParams = fn.parameters

   for (i in realFnParams.indices) {
      // 函数的参数类型
      val fnParamType = realFnParams[i].type
      // 实际传入的参数
      val realParamType = params[i]?.javaClass?.kotlin?.createType()!!
      require(
         fnParamType.toString() == realParamType.toString() ||
                 realParamType.isSubtypeOf(fnParamType)
      ) {
         "Parameter at index $i has incorrect type. Expected: $fnParamType, Actual: $realParamType"
      }
   }
}*/


